#include "key_event.h"
#include "FreeRTOS.h"
#include "hal_tty.h"
#include <stdio.h>

#define malloc  pvPortMalloc
#define free    vPortFree

typedef struct key_list_head {
    uint16_t key_count;
    key_event_t *head;
}key_list_head_t;

static key_list_head_t key_list_ = {0,NULL};

int8_t register_key_event(int mode,key_read_func read_f,key_event_func event_f) {

    if(read_f == NULL || event_f == NULL)
        return HAL_KEY_READ_EVENT_NULL;

    if(mode > BTN_MODE_PRESS)
        return HAL_KEY_MODE_ERROR;

    key_event_t *key_ = (key_event_t *)malloc(sizeof(key_event_t));
    if(key_ == NULL)
        return HAL_KEY_NO_MEMORY;

    key_->id = key_list_.key_count++;
    key_->mode = mode;
    key_->status = BTN_STATE_NONE;

    key_->clict_cnt = 0;
    key_->scan_cnt = 0;
    key_->event_cb = event_f;
    key_->read_func = read_f;

    key_->next = key_list_.head;
    key_list_.head = key_;

    return key_->id;
}

void key_event_process(key_event_t *key) {

    uint8_t status = key->status;
    switch(status) {
        case BTN_STATE_NONE:
			if(key->read_func()) {
				key->scan_cnt = 0;
				key->clict_cnt = 0;
				key->status = BTN_STATE_DOWN;
				if(key->mode == BTN_MODE_PRESS) {
					key->event_cb(key->id,BTN_PRESS_DOWN,0);
				}
			}
            break;
        case BTN_STATE_DOWN:
            if(key->read_func()) {
                key->scan_cnt++;
				if(key->mode < BTN_MODE_PRESS) {	
					if(key->scan_cnt >= 100) {       //Long 500ms
						key->event_cb(key->id,BTN_PRESS_LONG_CLICK,key->scan_cnt);
						key->status = BTN_STATE_WAIT;
					}
				}
            } else {
                if(key->mode == BTN_MODE_PRESS) {
                    key->event_cb(key->id,BTN_PRESS_UP,key->scan_cnt);
                    key->status = BTN_STATE_NONE;
                } else {
                    key->clict_cnt++;
                    if(key->clict_cnt >= 2) {
                        key->event_cb(key->id,BTN_PRESS_DOUBLE_CLICK,key->scan_cnt);
                        key->status = BTN_STATE_NONE;
                    } else {
                        key->scan_cnt = 0;
                        key->status = BTN_STATE_UP;
                    }
                }
            }
            break;
        case BTN_STATE_UP:
            if(key->read_func()) {
                key->scan_cnt = 0;
                key->status = BTN_STATE_DOWN;
            } else {
                key->scan_cnt++;
                if(key->scan_cnt > 60) {        ///< 60 * 5 > 300ms
                    key->event_cb(key->id,BTN_PRESS_CLICK,key->scan_cnt);
                    key->status = BTN_STATE_NONE;
                }
            }
            break;

        case BTN_STATE_WAIT:
			key->scan_cnt++;
            if(!key->read_func()) {
				key->event_cb(key->id,BTN_PRESS_LONG_CLICK_UP,key->scan_cnt);
                key->status = BTN_STATE_NONE;
            } else {			
				if(key->mode == BTN_MODE_CLICK_CHECK) {
					if(key->scan_cnt >= 24000) {       //Long 120s
						key->event_cb(key->id,BTN_PRESS_TOO_LONG,key->scan_cnt);
						key->status = BTN_STATE_FAULT;
					}
				}
			}
            break;
		case BTN_STATE_FAULT:
			if(!key->read_func()) {
				key->event_cb(key->id,BTN_PRESS_FAULT_CLEAR,key->scan_cnt);
				key->status = BTN_STATE_NONE;
			}
			break;
        default:
            break;
    }
}


void key_scan_process() {

    key_event_t *key = key_list_.head;
    while(key) {
        key_event_process(key);
        key = key->next;
    }
}

void key_list_destory() {
    
    key_event_t *key = key_list_.head;
    while(key) {
        key_event_t *tmp = key;
        key = key->next;
        free(tmp);
    }
    key_list_.key_count = 0;
}



